package cn.cyx.demo.chat.handler;

import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.*;
import io.netty.util.CharsetUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.InputStream;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;

/**
 * HTTP请求处理器
 * 
 * 这个类负责处理所有的HTTP请求，包括：
 * 1. 静态文件请求（CSS、JS、图片等）
 * 2. WebSocket升级请求
 * 3. 首页请求
 * 4. 404错误处理
 * 
 * 主要功能：
 * - 根据请求路径分发到不同的处理方法
 * - 支持静态文件服务
 * - 处理WebSocket握手
 * - 提供错误页面
 * 
 * @author cyx
 * @since 1.0.0
 */
public class HttpRequestHandler extends SimpleChannelInboundHandler<FullHttpRequest> {

    /** 日志记录器 */
    private static final Logger logger = LoggerFactory.getLogger(HttpRequestHandler.class);

    /** WebSocket路径 */
    private static final String WEBSOCKET_PATH = "/ws";

    /** MIME类型映射表，用于设置正确的Content-Type */
    private final Map<String, String> mimeTypes;

    /**
     * 构造函数
     * 初始化MIME类型映射表
     */
    public HttpRequestHandler() {
        this.mimeTypes = new HashMap<>();
        initializeMimeTypes();
    }

    /**
     * 初始化MIME类型映射表
     * 
     * MIME类型用于告诉浏览器如何解析返回的内容
     * 例如：text/html表示HTML文档，text/css表示CSS样式表
     */
    private void initializeMimeTypes() {
        // 文本类型文件
        mimeTypes.put("html", "text/html; charset=UTF-8");
        mimeTypes.put("css", "text/css; charset=UTF-8");
        mimeTypes.put("js", "application/javascript; charset=UTF-8");
        mimeTypes.put("json", "application/json; charset=UTF-8");

        // 图片类型文件
        mimeTypes.put("png", "image/png");
        mimeTypes.put("jpg", "image/jpeg");
        mimeTypes.put("jpeg", "image/jpeg");
        mimeTypes.put("gif", "image/gif");
        mimeTypes.put("ico", "image/x-icon");
    }

    /**
     * 处理HTTP请求的核心方法
     * 
     * 这个方法会根据请求的URI路径分发到不同的处理方法：
     * 1. 静态文件请求 -> handleStaticFile()
     * 2. 首页请求 -> handleIndexPage()
     * 3. 其他请求 -> handleNotFound()
     * 
     * 注意：WebSocket升级请求由WebSocketServerProtocolHandler处理
     * 
     * @param ctx     通道上下文，用于发送响应
     * @param request HTTP请求对象
     * @throws Exception 处理异常
     */
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest request) throws Exception {
        String uri = request.uri();
        logger.debug("收到HTTP请求: {}", uri);

        // 1. 处理静态文件请求（CSS、JS、图片等）
        if (uri.startsWith("/static")) {
            logger.debug("处理静态文件请求: {}", uri);
            handleStaticFile(ctx, request);
            return;
        }

        // 2. 处理首页请求
        if ("/".equals(uri) || "/index.html".equals(uri)) {
            logger.debug("处理首页请求");
            handleIndexPage(ctx, request);
            return;
        }

        // 3. 处理其他请求（返回404）
        logger.warn("未找到匹配的处理器，返回404: {}", uri);
        handleNotFound(ctx, request);
    }

    /**
     * 处理静态文件请求
     * 
     * 支持的文件类型：CSS、JS、图片等
     * 文件路径：/static/css/style.css、/static/js/chat.js等
     * 
     * 处理流程：
     * 1. 从URI中提取文件路径
     * 2. 从classpath中加载文件
     * 3. 设置正确的Content-Type
     * 4. 设置缓存头
     * 5. 返回文件内容
     * 
     * @param ctx     通道上下文
     * @param request HTTP请求
     */
    private void handleStaticFile(ChannelHandlerContext ctx, FullHttpRequest request) {
        String uri = request.uri();
        // 提取文件路径，去掉"/static"前缀
        String filePath = uri.substring("/static".length());

        // 如果路径为空或为"/"，默认返回index.html
        if (filePath.isEmpty() || "/".equals(filePath)) {
            filePath = "/index.html";
        }

        try {
            // 从classpath中加载静态文件
            URL resource = getClass().getResource("/static" + filePath);
            if (resource == null) {
                logger.warn("静态文件不存在: {}", filePath);
                handleNotFound(ctx, request);
                return;
            }

            // 读取文件内容
            try (InputStream inputStream = resource.openStream()) {
                byte[] content = inputStream.readAllBytes();
                String contentType = getContentType(filePath);

                // 创建HTTP响应
                FullHttpResponse response = new DefaultFullHttpResponse(
                        HttpVersion.HTTP_1_1,
                        HttpResponseStatus.OK,
                        Unpooled.wrappedBuffer(content));

                // 设置响应头
                response.headers().set(HttpHeaderNames.CONTENT_TYPE, contentType);
                response.headers().set(HttpHeaderNames.CONTENT_LENGTH, content.length);
                // 设置缓存头，提高性能
                response.headers().set(HttpHeaderNames.CACHE_CONTROL, "public, max-age=3600");

                // 发送响应
                ctx.writeAndFlush(response);
            }
        } catch (Exception e) {
            logger.error("处理静态文件失败: {}", filePath, e);
            handleNotFound(ctx, request);
        }
    }

    /**
     * 处理首页请求
     * 如果静态文件不存在，直接返回404错误
     * 
     * @param ctx     通道上下文
     * @param request HTTP请求
     */
    private void handleIndexPage(ChannelHandlerContext ctx, FullHttpRequest request) {
        try {
            // 尝试从classpath中加载静态HTML文件
            URL resource = getClass().getResource("/static/index.html");
            if (resource == null) {
                // 如果静态文件不存在，直接返回404错误
                logger.warn("静态文件不存在: /static/index.html");
                handleNotFound(ctx, request);
                return;
            }

            // 读取静态文件内容
            try (InputStream inputStream = resource.openStream()) {
                byte[] content = inputStream.readAllBytes();

                // 创建HTTP响应
                FullHttpResponse response = new DefaultFullHttpResponse(
                        HttpVersion.HTTP_1_1,
                        HttpResponseStatus.OK,
                        Unpooled.wrappedBuffer(content));

                // 设置响应头
                response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/html; charset=UTF-8");
                response.headers().set(HttpHeaderNames.CONTENT_LENGTH, content.length);

                // 发送响应
                ctx.writeAndFlush(response);
            }
        } catch (Exception e) {
            logger.error("处理首页失败", e);
            // 发生异常时返回404错误
            handleNotFound(ctx, request);
        }
    }

    /**
     * 处理404错误
     * 
     * 当请求的路径没有对应的处理器时，返回404错误页面
     * 
     * @param ctx     通道上下文
     * @param request HTTP请求
     */
    private void handleNotFound(ChannelHandlerContext ctx, FullHttpRequest request) {
        String content = "404 - 页面未找到";

        // 创建404响应
        FullHttpResponse response = new DefaultFullHttpResponse(
                HttpVersion.HTTP_1_1,
                HttpResponseStatus.NOT_FOUND,
                Unpooled.copiedBuffer(content, CharsetUtil.UTF_8));

        // 设置响应头
        response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/plain; charset=UTF-8");
        response.headers().set(HttpHeaderNames.CONTENT_LENGTH, content.getBytes(CharsetUtil.UTF_8).length);

        // 发送响应并关闭连接
        ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
    }

    /**
     * 根据文件扩展名获取MIME类型
     * 
     * MIME类型告诉浏览器如何解析文件内容：
     * - text/html：HTML文档
     * - text/css：CSS样式表
     * - application/javascript：JavaScript文件
     * - image/png：PNG图片
     * 
     * @param filePath 文件路径
     * @return MIME类型字符串
     */
    private String getContentType(String filePath) {
        // 查找最后一个点号，获取文件扩展名
        int lastDot = filePath.lastIndexOf('.');
        if (lastDot > 0) {
            // 提取扩展名并转换为小写
            String extension = filePath.substring(lastDot + 1).toLowerCase();
            // 从MIME类型映射表中查找，如果找不到则返回默认类型
            return mimeTypes.getOrDefault(extension, "application/octet-stream");
        }
        // 如果没有扩展名，返回默认类型
        return "application/octet-stream";
    }
}